package com.block.channel.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.block.channel.enums.ReportChannelEnum;
import com.block.channel.enums.ReportTypeEnum;
import com.block.channel.factory.ReportChannelFactory;
import com.block.channel.flow.IChannelReportService;
import com.block.channel.model.result.ReprotFlowResult;
import com.block.common.bean.CommonParam;
import com.block.common.enums.ChargeTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.service.LogFactory;
import com.block.db.entity.ChannelBaseInfo;
import com.block.db.entity.ChannelFlowReportInfo;
import com.block.db.mapper.ChannelFlowReportInfoMapper;
import com.block.channel.service.IChannelFlowReportInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;

/**
 * <p>
 * 渠道信息流上报 服务实现类
 * </p>
 *
 * @author 
 * @since 2023-10-23
 */
@Service
public class ChannelFlowReportInfoServiceImpl extends ServiceImpl<ChannelFlowReportInfoMapper, ChannelFlowReportInfo> implements IChannelFlowReportInfoService {

    private static Logger log = LogFactory.getCommLog();

    @Autowired
    NotifyExceptionService notifyExceptionService;

    @Override
    public ChannelFlowReportInfo saveInitFlowInfo(CommonParam commonParam, ReportTypeEnum reportTypeEnum, Long uid){
        ChannelFlowReportInfo reportInfo = new ChannelFlowReportInfo();
        reportInfo.setDateInfo(LocalDate.now().toString());
        reportInfo.setChannelCode(commonParam.getChannelCode());
        reportInfo.setChannelName(commonParam.getChannelName());
        reportInfo.setUid(uid);
        reportInfo.setType(reportTypeEnum.getValue());
        boolean save = this.save(reportInfo);
        if (save){
            return this.getById(reportInfo.getId());
        }
        return null;
    }

    @Async
    @Override
    public void handleFlowReport(CommonParam commonParam, Long uid, ReportTypeEnum reportTypeEnum){

        try {

            commonParam.setUid(uid);

            // 判断渠道是否需要上报
            ChannelBaseInfo channelBaseInfo = commonParam.getChannelBaseInfo();
            log.info("【渠道信息上报】开始监测【channelCode】{}【uid】{}【reportTypeEnum】{}【commonParam】{}",
                    channelBaseInfo.getChannelCode(), uid, reportTypeEnum.getValue(), JSON.toJSONString(commonParam));

            if (!ObjectUtil.equals(channelBaseInfo.getChargeType(), ChargeTypeEnum.FLOW.getValue())){
                return;
            }
            if (!ReportChannelEnum.hasKey(channelBaseInfo.getChannelCode())){
                return;
            }

            // 新增上报记录
            ChannelFlowReportInfo reportInfo = this.saveInitFlowInfo(commonParam, reportTypeEnum, uid);

            // 上报概率判断
            double randomDouble = RandomUtil.randomDouble(1);
            BigDecimal randomRate = new BigDecimal(randomDouble).setScale(2, RoundingMode.HALF_UP);
            if (randomRate.compareTo(channelBaseInfo.getChannelRate()) > 0 ){
                ChannelFlowReportInfo updateEntity = new ChannelFlowReportInfo();
                updateEntity.setId(reportInfo.getId());
                updateEntity.setResultCode("-1");
                updateEntity.setResultMessage(StrUtil.format("扣量，不做处理；【随机数】{}【渠道比率】{}", randomRate, channelBaseInfo.getChannelRate()));
                updateEntity.setStatus("NOTHANDLE");
                this.updateById(updateEntity);
                return;
            }

            ReprotFlowResult flowResult = null;
            IChannelReportService service = ReportChannelFactory.getService(channelBaseInfo.getChannelCode());
            if (ObjectUtil.equals(reportTypeEnum.getValue(), ReportTypeEnum.REGISTER.getValue())){
                flowResult = service.registerActionReport(commonParam, channelBaseInfo);
            }
            if (ObjectUtil.equals(reportTypeEnum.getValue(), ReportTypeEnum.SOURCE.getValue())){
                flowResult = service.sourceActionReport(commonParam, channelBaseInfo);
            }
            log.info("【渠道信息上报】上报结束【channelCode】{}【uid】{}【reportTypeEnum】{}【flowResult】{}",
                    channelBaseInfo.getChannelCode(), uid, reportTypeEnum.getValue(), JSON.toJSONString(flowResult));
            if (ObjectUtil.isEmpty(flowResult)){
                return;
            }

            ChannelFlowReportInfo updateEntity = new ChannelFlowReportInfo();
            updateEntity.setId(reportInfo.getId());
            updateEntity.setResultCode(flowResult.getCode());
            updateEntity.setResultMessage(flowResult.getMessage());
            updateEntity.setParamInfo(flowResult.getParamInfo());
            updateEntity.setResultInfo(flowResult.getResultInfo());
            if (flowResult.isSuccess()){
                updateEntity.setStatus("SUCCESS");
            }else {
                updateEntity.setStatus("FAILED");
            }
            this.updateById(updateEntity);

        }catch (Exception exception){
            exception.printStackTrace();
            String message = StrUtil.format("【uid】{}【reportType】{}【CommonParam】{}",
                    uid, reportTypeEnum.getName(), JSON.toJSONString(commonParam));
            notifyExceptionService.notifyNoticeInfo("CHANNEL_REPORT", "信息流数据上报异常", message, exception);
        }
    }
}
